package Server

import (
	"net"
	"sync"
	"log"
	"GoRProxy/Utils"
	"strings"
	"math/rand"
	"fmt"
	"time"
)

// 连接表
var connectionPool = make(map[string]net.Conn)

// 等待连接表
var waittingConnectionPool = make(map[int32]net.Conn)

// 锁
var channelLock = sync.Mutex{}

func ListenServerPost(localPort string) {
	log.Println(" Start listen  on port : " + localPort)
	listener, err := net.Listen("tcp", ":"+localPort)
	if err != nil {
		log.Println(err, "func listenPost(localPort string)")
		panic(err)
	}
	log.Println("Listen on port  : "+localPort, listener.Addr().String(), listener.Addr().Network())
	//循环监听
	for {
		conn, err := listener.Accept()
		if err != nil {
			log.Println(err, "func listenPost(localPort string)")
			conn.Close()
		} else {
			log.Println("Get a new connection !!!  address ", conn.RemoteAddr().String(),
				" localAddress : "+conn.LocalAddr().String())
			go handleClient(conn)
		}

	}
}

// 提供服务器端口 并监听 处理反代.
func ListenConnction(aPorts []string) {
	for _, port := range aPorts {
		log.Println(" log ~~~~~~~~~~~~ port : ", port)
		go listenGuestPort(port)
	}
}

func handleClient(conn net.Conn) error {
	log.Println("Starting handle Client ... ")
	request := make([]byte, 1)
	conn.Read(request)

	cmd := request[0]
	switch cmd {
	//注册服务 否则处理其请求.
	case Utils.CMD_REGISTER_CLIENT_REQUEST:
		log.Println("Utils.CMD_REGISTER_CLIENT_REQUEST", Utils.CMD_REGISTER_CLIENT_REQUEST)
		portBuffer := make([]byte, 1024)
		conn.Read(portBuffer)
		portStr := string(portBuffer)
		portStr = strings.Trim(portStr, "\x00")
		log.Println("Port service from client:", portStr)
		response := make([]byte, 1)
		response[0] = Utils.CMD_REGISTER_CLIENT_RESPONSE
		conn.Write(response)
		// 更新 连接表
		services := strings.Split(portStr, ",")
		for _, v := range services {
			oldConn := connectionPool[v]
			if oldConn != nil {
				oldConn.Close()
				oldConn = nil
			}
			connectionPool[v] = conn
			log.Println("注册成功... ")
		}
		go processConn(conn)
	case Utils.CMD_CLIENT_REPLY_SESSION_REQUEST:
		log.Println("Utils.CMD_CLIENT_REPLY_SESSION_REQUEST", Utils.CMD_CLIENT_REPLY_SESSION_REQUEST)
		log.Println("Got a session connection from client:", conn.RemoteAddr().String())
		request = make([]byte, 4)
		conn.Read(request)
		sessionID := Utils.BytesToInt32(request)
		log.Println("Get session id from client:", sessionID)
		response := make([]byte, 1)
		response[0] = Utils.CMD_CLIENT_REPLY_SESSION_RESPONSE
		conn.Write(response)
		log.Println("Send client reply session response")
		guestConn := waittingConnectionPool[sessionID]
		log.Println("Get guest connection from pool:", guestConn)
		delete(waittingConnectionPool, sessionID)
		if guestConn != nil {
			Utils.ConnectionExchange(conn, guestConn)
		}
	default:
		log.Println(" ukonw command ...")

	}

	return nil
}

func processConn(conn net.Conn) {
	for {
		buffer := make([]byte, 1)
		_, err := conn.Read(buffer)
		if err != nil {
			log.Println("Failed to read from client, ", err)
			conn.Close()
			return
		}
		cmd := buffer[0]
		switch cmd {
		case Utils.CMD_HEART_BEAT_REQUEST:
			log.Println("Get heartbeat request from client " + conn.RemoteAddr().String())
			rsp := []byte{Utils.CMD_HEART_BEAT_RESPONSE}
			channelLock.Lock()
			log.Println("Response heartbeat to client : " + conn.RemoteAddr().String())
			_, err = conn.Write(rsp)
			channelLock.Unlock()
			if err != nil {
				log.Println("Failed to write client")
				conn.Close()
				return
			}
		case Utils.CMD_SERVER_START_SESSION_RESPONSE:
			//暂时不处理
			log.Println("Utils.CMD_SERVER_START_SESSION_RESPONSE", Utils.CMD_SERVER_START_SESSION_RESPONSE)
		default:

		}
	}
}

func listenGuestPort(port string) {
	log.Println("start listen port for guest " + port)
	listener, e := net.Listen("tcp", ":"+port)
	if e != nil {
		log.Println(" Fail to listen on port :" + port)
		panic(e)
	}
	log.Println("Listen on port for guest : ", port, listener.Addr().(*net.TCPAddr).IP)
	defer listener.Close()

	// 循环监听请求
	// 接收到请求则 进行处理
	for {
		guestConn, err := listener.Accept()
		//处理新连接..
		// 如果连接失败则关闭连接继续监听.
		if err != nil {
			log.Println("fail to  Accept connection on port : ", listener.Addr().(*net.TCPAddr).Port)
			guestConn.Close()
		} else { // 如果连接成功则  提供反代.
			log.Println(" get a connection for guest", guestConn.RemoteAddr())
			//从连接池获取对应的连接 如果未注册则不提供服务
			conn := connectionPool[port]
			if conn != nil {
				doReverseProxy(conn, guestConn, port)
			} else {
				log.Println("No client register for this port, close guest.")
				guestConn.Close()
			}
		}
	}
}

// 执行反代.
func doReverseProxy(conn net.Conn, guestConn net.Conn, guestPort string) {
	var seesionID = rand.Int31()
	channelLock.Lock()
	err := serverStartSessionRequest(conn, seesionID, guestPort)
	channelLock.Unlock()
	if err == nil {
		log.Println(" Get correct response , begin start session ")
		waittingConnectionPool[seesionID] = guestConn
		go timeoutHandle(seesionID)
	} else {
		log.Println(" Invalid response ... ", err)
	}

}

func serverStartSessionRequest(conn net.Conn, requestId int32, guestPort string) error {
	fmt.Println(" serverStartSessionRequest ")
	cmd := []byte{Utils.CMD_SERVER_START_SESSION_REQUEST}
	var data = append(cmd, Utils.Int32ToBytes(requestId)...)
	data = append(data, []byte(guestPort)...)
	conn.Write(data)
	return nil
}

func timeoutHandle(sessionID int32) {
	time.Sleep(5 * time.Second)
	conn, ok := waittingConnectionPool[sessionID]
	if ok {
		log.Println("Timeout out to wait for connection from client, close the guest.")
		conn.Close()
		delete(waittingConnectionPool, sessionID)
	}
}
